import ISprite, { MouseEventHandler, KeyboardEventHandler, UpdateEventHandler, RenderEventHandler } from "../interfaces/ISprite";
import ERenderType from "../enums/ERenderType";
import Transform2D from "../maths/Transform2D";
import IShape from "../interfaces/IShape";
import ISpriteContainer from "../interfaces/ISpriteContainer";
import Matrix2D from "../maths/Matrix2D";
import EOrder from "../enums/EOrder";
import Vector2 from "../maths/Vector2";
import SpriteNode from "./SpriteNode";
import TreeNode from "../core/TreeNode";

export default class Sprite2D implements ISprite {

    // 然后旋转，最后一个参数false，表示rotation是角度而不是弧度
    public showCoordSystem: boolean = false;
    public renderType: ERenderType = ERenderType.FILL;
    public isVisible: boolean = true;
    public fillStyle: string | CanvasGradient | CanvasPattern = 'white';
    public strokeStyle: string | CanvasGradient | CanvasPattern = 'black';
    public lineWidth: number = 1.0;
    // ITransformable接口的成员属性和方法都委托到Transform2D来实现
    public transform: Transform2D = new Transform2D();
    // ISprite接口本身的成员属性
    public name: string;
    public shape: IShape;
    public owner!: ISpriteContainer;
    public data: any;

    // 事件回调
    public mouseEvent: MouseEventHandler | null = null;
    public keyEvent: KeyboardEventHandler | null = null;
    public updateEvent: UpdateEventHandler | null = null;
    public renderEvent: RenderEventHandler | null = null;

    public set x(x: number) {
        this.transform.position.x = x;
    }

    public get x(): number {
        return this.transform.position.x;
    }

    public set y(y: number) {
        this.transform.position.y = y;
    }

    public get y(): number {
        return this.transform.position.y;
    }

    public set rotation(rotation: number) {
        this.transform.rotation = rotation;
    }

    public get rotation(): number {
        return this.transform.rotation;
    }

    public set scaleX(s: number) {
        this.transform.scale.x = s;
    }

    public get scaleX(): number {
        return this.transform.scale.x;
    }

    public set scaleY(s: number) {
        this.transform.scale.y = s;
    }

    public get scaleY(): number {
        return this.transform.scale.y;
    }

    public getWorldMatrix(): Matrix2D {
        // 使用js instanceof 操作符，能判断this . owner是不是SpriteNode类的对象
        // 如果是，则获取当前精灵到根节点精灵合成的局部-全局变换矩阵
        if (this.owner instanceof SpriteNode) {
            let arr: TreeNode<ISprite>[] = [];
            let curr: TreeNode<ISprite> | undefined = this.owner as SpriteNode;
            while (curr !== undefined) {
                //从当前的节点到root节点记录在arr中
                arr.push(curr);
                curr = curr.parent;
            }

            let out: Matrix2D = Matrix2D.create();
            let currMat: Matrix2D;
            // 这时候，arr中的内容如:[this，parent，...，root];
            // 但是要进行从局部到全局的矩阵合成操作
            // 因此需要矩阵乘法的顺序为 root * ... * parent
            for (let i: number = arr.length - 1; i >= 0; i--) {
                curr = arr[i];
                if (curr.data) {
                    // transform2D类并没有公开给ISprite接口，因此需要用
                    // as关键词进行向下转型操作
                    currMat = (curr.data as Sprite2D).transform.toMatrix();
                    Matrix2D.multiply(out, currMat, out);
                }
            }
            return out;
        } else {
            return this.transform.toMatrix();
        }
    }
    public getLocalMatrix(): Matrix2D {
        let src: Matrix2D = this.getWorldMatrix();
        let out: Matrix2D = Matrix2D.create();
        if (Matrix2D.invert(src, out)) {
            return out;
        } else {
            alert('矩阵求逆失败');
            throw new Error('矩阵求逆失败');
        }
    }

    public constructor(shape: IShape, name: string) {
        this.name = name;
        this.shape = shape;
    }

    update(mesc: number, diff: number, order: EOrder): void {
        // 如果当前精灵有挂接updateEvent，则触发该事件
        if (this.updateEvent) {
            this.updateEvent(this, mesc, diff, order);
        }
    }

    hitTest(localPt: Vector2): boolean {
        if (this.isVisible) {
            //要将光标点变换到局部坐标系
            return this.shape.hitTest(localPt, this);
        } else {
            return false;
        }
    }
    // 委托调用IShape对应的draw方法（IDrawable接口）
    // 而IShape接口的beginDraw、draw、endDraw方法依赖ITransform和IRenderState接口
    // 如有必要同时会触发renderEvent事件
    draw(context: CanvasRenderingContext2D): void {
        if (this.isVisible) {
            // 渲染状态进栈
            // 然后设置渲染状态及当前变换矩阵
            this.shape.beginDraw(this, this, context);
            // 在Draw之前，触发PREORDER渲染事件
            if (this.renderEvent !== null) {
                this.renderEvent(this, context, EOrder.PREORDER);
            }
            // 调用主要的绘图方法
            this.shape.draw(this, this, context);
            // 在Draw之后，触发POSTORDER渲染事件
            if (this.renderEvent !== null) {
                this.renderEvent(this, context, EOrder.POSTORDER);
            }
            // 恢复渲染状态
            this.shape.endDraw(this, this, context);
        }
    }
}